﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Util;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Hexacell {
    public class NeighborKillerBoard : Board {

        public Texture2D MarbleTexture { get; set; }

        protected Marble[,] marbles;

        public NeighborKillerBoard(Game1 game, int cellCountX, int cellCountY, Texture2D marbleTexture) : base(game, cellCountX, cellCountY, false) {

            MarbleTexture = marbleTexture;

            marbles = new Marble[cellCountX, cellCountY];

            for (int y = 0; y < CellCount.Y; ++y) {
                for (int x = 0; x < CellCount.X; ++x) {
                    marbles[x, y] = new Marble(game.Random);
                }
            }
        }

        protected void adjacentMarbles(IntVector2 origin, List<IntVector2> checkedMarbles, List<IntVector2> matchingMarbles) {
            if (checkedMarbles == null) {
                checkedMarbles = new List<IntVector2>();
                checkedMarbles.Add(origin);
                matchingMarbles.Add(origin);
            }
            
            List<IntVector2> neighbors = this.neighbors(origin);
            foreach (var neighbor in neighbors) {
                if (!checkedMarbles.Contains(neighbor)) {
                    checkedMarbles.Add(neighbor);
                    Marble neighborMarble = marbles[neighbor.X, neighbor.Y];
                    if (neighborMarble != null) {
                        Marble originMarble = marbles[origin.X, origin.Y];
                        if (neighborMarble.Type == originMarble.Type) {
                            matchingMarbles.Add(neighbor);
                            adjacentMarbles(neighbor, checkedMarbles, matchingMarbles);
                        }
                    }
                }
            }
        }

        protected void killMarble(IntVector2 coordinates) {
            marbles[coordinates.X, coordinates.Y] = null;
            /*
            for (int y = coordinates.Y - 1; y >= 0; --y) {
                marbles[coordinates.X, y + 1] = marbles[coordinates.X, y];
                if (y == 0) {
                    marbles[coordinates.X, 0] = null;
                }
            }
            */
        }

        public void pickMarble(IntVector2 coordinates) {
            if (marbles[coordinates.X, coordinates.Y] != null) {
                List<IntVector2> matchingMarbles = new List<IntVector2>();
                adjacentMarbles(coordinates, null, matchingMarbles);

                //kill adjacent marbles
                for (int y = 0; y < CellCount.Y; ++y) {
                    for (int x = 0; x < CellCount.X; ++x) {
                        IntVector2 marbleCoords = new IntVector2(x, y);
                        if (matchingMarbles.Contains(marbleCoords)) {
                            killMarble(marbleCoords);
                        }
                    }
                }

                for (int x = 0; x < CellCount.X; ++x) {
                    for (int y = CellCount.Y - 1; y >= 0; --y) {
                        if (marbles[x, y] == null) {
                            int i = 0;
                            for (int y2 = y - 1; y2 >= 0; --y2) {
                                if (marbles[x, y2] != null) {
                                    CellTransition down = new CellTransition(false, 0.03f);
                                    down.Source = new IntVector2(x, y2);
                                    down.Destination = new IntVector2(x, y-i);
                                    cellTransitions.Add(down);
                                    ++i;
                                }
                            }
                            break;
                        }
                    }
                }
            }
        }

        protected Marble marbleAtCell(IntVector2 v) {
            return marbles[v.X, v.Y];
        }

        protected Marble marbleAtCell(int x, int y) {
            return marbles[x, y];
        }

        public override void Update(GameTime gameTime) {
            base.Update(gameTime);

            List<CellTransition> zombies = new List<CellTransition>();

            foreach(CellTransition ct in cellTransitions) {
                ct.update(gameTime);
                if (ct.isCompleted()) {
                    zombies.Add(ct);
                }
            }

            foreach (var ct in zombies) {
                marbles[ct.Destination.X, ct.Destination.Y] = marbleAtCell(ct.Source);
                marbles[ct.Source.X, ct.Source.Y] = null;
                cellTransitions.Remove(ct);
            }
        }

        override public void Draw() {
            SpriteBatch spriteBatch = game.SpriteBatch;
            float r = CellRadius;

            float layerDepth = game.LayerManager.Depth((int)MainLayer.Board);

            for (int y = 0; y < CellCount.Y; ++y) {
                for (int x = 0; x < CellCount.X; ++x) {
                    IntVector2 cell = new IntVector2(x, y);
                    Marble marble = marbles[x, y];
                    Vector2 position = centerOfCell(cell);
                    if (marble != null) {
                        //Primitive2.DrawCircle(spriteBatch, position, r - 1, colorForMarble(marble), true, layerDepth);
                        float scale = 2.0f * r / MarbleTexture.Height * 0.995f;
                        Vector2 origin = MarbleTexture.GetSize() * 0.5f;

                        float yAnimOffset = 0;
                        foreach(var ct in cellTransitions) {
                            if(ct.Source == cell) {
                                yAnimOffset = (ct.Destination.Y - ct.Source.Y) * r*2.0f * ct.Completion;
                            }
                        }
                        position.Y += yAnimOffset;

                        spriteBatch.Draw(MarbleTexture, position, null, marble.color(), 0.0f, origin, scale, SpriteEffects.None, layerDepth);
                    } else {
                        //Primitive2.DrawCircle(spriteBatch, position, r - 1, Color.Black, false, layerDepth);
                    }
                }
            }
        }
    }
}
